package com.godenwater.recv.handler;

import java.io.File;
import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;
import java.util.*;

import cn.gov.mwr.sl651.*;
import cn.gov.mwr.sl651.parser.AscParser;
import cn.gov.mwr.sl651.parser.HexParser;
import com.godenwater.core.spring.Application;
import com.godenwater.recv.manager.SessionIoFutureListener;
import com.godenwater.recv.spring.Configurer;
import com.godenwater.recv.model.CommonMessage;
import org.apache.commons.lang3.StringUtils;
import org.apache.mina.core.future.WriteFuture;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.gov.mwr.sl651.command.DownCommand;
import cn.gov.mwr.sl651.header.HexHeader;
import cn.gov.mwr.sl651.utils.ByteUtil;
import cn.gov.mwr.sl651.utils.CRC16Helper;
import cn.gov.mwr.sl651.utils.StcdParser;

import com.godenwater.recv.RecvConstant;
import com.godenwater.recv.server.all.RtuConfig;
import com.godenwater.recv.server.all.RtuServer;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * SL651协议的处理器
 *
 * @author admin
 */
public class Sl651MessageHandler extends AbstractHandler {

    private static Logger logger = LoggerFactory.getLogger(Sl651MessageHandler.class);
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");
    RedisTemplate redisTemplate;

    /**
     * Returns a singleton Sl651MessageHandler instance.
     *
     * @return a Sl651MessageHandler instance.
     */
    public static Sl651MessageHandler getInstance() {
        return Sl651MessageHandlerContainer.instance;
    }

    // Wrap this guy up so we can mock out the UserManager class.
    private static class Sl651MessageHandlerContainer {
        private static Sl651MessageHandler instance = new Sl651MessageHandler();
    }

    private Sl651MessageHandler() {

    }

    /**
     * 根据设备号获取redis缓存中的测站基本信息 - 针对标准协议
     *
     * @param stcd
     * @return
     */
    public String getStationByStcd(String stcd) {
        long st1 = System.currentTimeMillis();

        redisTemplate = (RedisTemplate) Application.getInstance().getCtx().getBean("redisTemplate");
        String onLine = "0";
        try {
            if (redisTemplate == null) {
                logger.info(">> 无监控终端！");
            } else {
                onLine = redisTemplate.opsForValue().get(stcd + "Online") == null ? "0" : (String) redisTemplate.opsForValue().get(stcd + "Online");
            }
        } catch (Exception ex) {
            RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
            throw new RuntimeException(ex);
        }
        long st2 = System.currentTimeMillis();

        return onLine;
    }

    public void perform(String channel, IoSession session, CommonMessage message, int recvPort) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式

        byte[] funcCode;
        byte mode;
        byte[] stationAddr;
        byte[] password;
        byte[] centerAddr;
        String stcd;// 此处有问题，若是多个测站共用一个测站编码，会出现召测不到信息的情况。
        boolean crcFlag = true;
        String replyMsgLog = "";
        cn.gov.mwr.sl651.IMessageHeader header = (cn.gov.mwr.sl651.IMessageHeader) message.getHeader();
        funcCode = header.getFuncCode();
        mode = header.getBodyStartBit()[0];
        stationAddr = header.getStationAddr();
        centerAddr = header.getCenterAddr();
        password = header.getPassword();
        stcd = StcdParser.parseStcd(stationAddr);// 此处有问题，若是多个测站共用一个测站编码，会出现召测不到信息的情况。
        long st1 = System.currentTimeMillis();

        // 3、应答回复或重发报文请求
        byte[] replyMsg = null;

        // 如果上行的是升级程序回复，则需要下发升级报文，则在此做回复，此处为2016-12-06添加
        if (funcCode[0] == (byte) 0xE2) {// M1模式，无需应答
            // 判断如果是正常的上行报文，则下发升级程序命令

            // 判断如果是丢包命令，则下发丢包的报文

            // 发送如果是升级完成的回复，则更新状态

        }

        // 1、模式选择，如果是2F表示为M1模式，不需要应答
        if (funcCode[0] != (byte) 0x2F) {// M1模式，无需应答

            // 1、 校验消息
            //logger.debug("校验报文，开始校验CRC...  ");
            crcFlag = checkCRC(message);// 校验消息体，CRC校验

            // 2、 存放于消息队列中，等待处理。将队列放在此处，减少了对链接报的处理
            // 2、将消息存放在日志文件中
            /**
             * ChannelMessage cm = new ChannelMessage(); cm.setChannel(channel);
             * cm.setMessage(message); cm.setCrcFlag(crcFlag); //
             * server.queuePush(cm); RtuServer.getInstance().getMessageManager()
             * .append(Constant.SL651, cm);
             */

            // 3、回复消息
            // M2模式
            if (mode == Symbol.STX) {
                if (crcFlag) {
                    // 确认应答
                    logger.debug("校验结果，报文CRC验证<相一致>，M2模式发送\"应答\"回复....");
                    replyMsg = replyMessage(session, message);
                } else {
                    // 重发请求
                    logger.debug("校验结果，报文CRC验证\"不一致 \"，M2模式发送\"重发\"请求....");
                    replyMsg = repeatMessage(message);
                }
            }

            // M3模式,最后一条报文才进行应答，然后后再考虑重发
            if (mode == Symbol.SYN
                    && (channel.equalsIgnoreCase("GPRS") || channel
                    .equalsIgnoreCase("UDP"))) {
                if (crcFlag) {
                    // 最后一个再确认应答，应答后再检查是否有错误包，有错误包，再发送重发请求
                    logger.debug("校验结果，报文CRC验证相一致，M3模式发送应答回复....");
                    // HydroServer.getInstance().getMonitorManager().append(log);

                    // 判断是否为最后一条报文，如果是，才进行回复
                    replyMsg = replyMessage(session, message);
                    // 重发错误报文请求
                    // repeatMessage();
                } else {
                    // 有错误包，需进行记录
                    logger.debug("校验结果，报文CRC验证不一致，M3模式发送重发请求....");
                    // HydroServer.getInstance().getMonitorManager().append(log);
                    // server.saveErrMessage(msg);
                }
            }
            IParser parser;
            if (header.getStartBit()[0] == Symbol.SOH_ASC) {
                parser = new AscParser();
            } else {
                parser = new HexParser();
            }


        }

        if (replyMsg != null) {
            logger.debug("回复报文，" + ByteUtil.toHexString(replyMsg) + "");
            replyMsgLog += ByteUtil.toHexString(replyMsg);
            if (funcCode[0] != (byte) 0x2F) {// M1模式，无需应答
                //logger.info("S> " + ByteUtil.toHexString(replyMsg) + "");
            }
            session.write(replyMsg);
        }
        long st2 = System.currentTimeMillis();
        if (stcd != null && stcd.equals("0000006721")) {
            logger.info(stcd + "回复后执行时间--" + df.format(new Date()) + "  耗时:" + (st2 - st1));
        }
        // 4、将测站与session关联起来
        RtuServer.getInstance().getSessionManager().bindSession(session, RecvConstant.SL651, stcd);
        //中心站地址和密码写入到缓存
        Boolean setStF0 = (Boolean) Configurer.getBooleanProperty("setStF0", false);
        if (setStF0) {
            setStcdf01(stcd, ByteUtil.toHexString(centerAddr), ByteUtil.toHexString(password));
        }
        // 5、水文通信规约畅通率计算
        // rateMessage(channel, funcCode[0], stcd);

        // 6、前台监测通知
        String logMsg = viewMessage(message);
        // monitorMessage(channel, stcd, logMsg);
        if (funcCode[0] != (byte) 0x2F) {// M1模式，无需应答
            //整点校时
          /*  String hexMessage =stcd;
            hexMessage = hexMessage.substring(0, 32) + sdf.format(new Date()) + "05";
            byte[] crcResult = CRC16Helper.crc16Check(ByteUtil.HexStringToBinary(hexMessage));
            hexMessage = hexMessage + ByteUtil.byteToHexString(crcResult);
            byte[] byteMessage = ByteUtil.HexStringToBinary(hexMessage);
            session.write(byteMessage);*/

            // 7、 写入报文记录
            String ip = "";
            Integer port = 0;
            try {
                ip = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
                port = ((InetSocketAddress) session.getRemoteAddress()).getPort();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            long st4 = System.currentTimeMillis();
          /* if (stcd != null && stcd.equals("0000006721")) {
                logger.info(stcd + "保存前--" + df.format(new Date()) + "  耗时:" + (st4 - st1));
            }
            if (stcd.equals("0000008165")) {
                logger.info("识别站号-----------0000008165识别站号-----------");
            }   *
           */
            //logger.info("识别站号-----------" + stcd + "识别站号-----------");
            saveMessage(channel, RecvConstant.SL651, stcd, crcFlag, logMsg, "0", replyMsgLog, ip, port, ByteUtil.toHexString(funcCode), recvPort);


        }
       /* long st5 = System.currentTimeMillis();
        if (stcd != null && stcd.equals("0000006721")) {
            logger.info(stcd + "结束处理数据--" + df.format(new Date()) + "  耗时:" + (st5 - st1));
        }*/

    }

    public void downloadMsg(IoSession session, String stcd) {
        String callMsg = redisManager.read(stcd + "Callder");
        if (callMsg.length() > 0) {
            //判断是否有多个连接 如果有，是不是最后一个 如果是则下发 否则 重新塞入redis
            String[] callMsgList = callMsg.split("#");
            String retuCd = callMsgList[0];//设备号
            String id = callMsgList[1];//数据库ID
            String fun = callMsgList[2];//功能码
            String msg = callMsgList[3];//下发报文
            if (StringUtils.equalsIgnoreCase(fun, "4A")) {
                // 替换时间部分，并重新生成校验码，然后下发
                msg = msg.substring(0, 32) + sdf.format(new Date()) + "05";
                byte[] crcResult = CRC16Helper.crc16Check(ByteUtil.HexStringToBinary(msg));
                msg = msg + ByteUtil.byteToHexString(crcResult);
            }
            byte[] byteMessage = ByteUtil.HexStringToBinary(msg);
            // 得有一个标志，标志当前的会话已经超时，RTU对方可能没有在上电状态。
            if (!session.isClosing()) {
                //logger.info("C> " + hexMessage);
                WriteFuture f = session.write(byteMessage);
                logger.info(">> 开始下发【召测消息】到 " + stcd + " 到客户端，远程地址为：" + session.getRemoteAddress() + "！");
                // 发送成功后，需要写入成功标识
                f.addListener(new SessionIoFutureListener(RecvConstant.SL651, id, stcd));
                redisManager.writer("replay", id);

            } else {
                redisManager.writer(stcd + "Callder", callMsg);
            }


        }
    }

    public void setStcdf01(String stcd, String f01, String f03) {
        //添加测站的中心站地址和密码到redis
        redisManager.setRedisPwd(stcd, f01, f03);
    }

    private String cmdNormal(byte[] stcd, byte[] center, byte funcCode) throws Exception {


        DownCommand cmd = new DownCommand();

        cmd.setStartBit(Symbol.SOH_HEX);
        cmd.setCenterAddr(center);// 中心站地址，以16进制位数保存，四字节
        cmd.setStationAddr(stcd);
        cmd.setPassword(ByteUtil.HexStringToBinary("0999"));
        cmd.setBodyStartBit(Symbol.STX);
        cmd.setEof(Symbol.ENQ);
        cmd.setFuncCode(new byte[]{funcCode});
        IMessage message = cmd.send37Message(0, null);

        // 开始发送召测，并写入数据库
        String hexMessage = cmd.printHexString(message);
        return hexMessage;
    }

    private String cmdNormal(byte[] stcd, byte[] center, byte funcCode, byte[] pwd, String tm) throws Exception {


        DownCommand cmd = new DownCommand();

        cmd.setStartBit(Symbol.SOH_HEX);
        cmd.setCenterAddr(center);// 中心站地址，以16进制位数保存，四字节
        cmd.setStationAddr(stcd);
        cmd.setPassword(pwd);
        cmd.setBodyStartBit(Symbol.STX);
        cmd.setEof(Symbol.ENQ);
        cmd.setFuncCode(new byte[]{funcCode});
        IMessage message = cmd.send37Message(0, tm);

        // 开始发送召测，并写入数据库
        String hexMessage = cmd.printHexString(message);
        return hexMessage;
    }

    /**
     * 水文协议CRC校验
     *
     * @param message
     * @return
     */
    public boolean checkCRC(CommonMessage message) {

        IMessageHeader header = (IMessageHeader) message.getHeader();
        byte[] body = message.getContent();

        byte[] bytes = new byte[header.getLength() + body.length + 1];

        int pos = 0;
        System.arraycopy(header.getStartBit(), 0, bytes, pos,
                header.getStartBit().length);
        pos = pos + header.getStartBit().length; // 此处将取值直接改为取数据中字节的长度，对字节处理更精确

        System.arraycopy(header.getCenterAddr(), 0, bytes, pos,
                header.getCenterAddr().length);
        pos = pos + header.getCenterAddr().length;

        System.arraycopy(header.getStationAddr(), 0, bytes, pos,
                header.getStationAddr().length);
        pos = pos + header.getStationAddr().length;

        System.arraycopy(header.getPassword(), 0, bytes, pos,
                header.getPassword().length);
        pos = pos + header.getPassword().length;

        System.arraycopy(header.getFuncCode(), 0, bytes, pos,
                header.getFuncCode().length);
        pos = pos + header.getFuncCode().length;

        System.arraycopy(header.getBodySize(), 0, bytes, pos,
                header.getBodySize().length);
        pos = pos + header.getBodySize().length;

        System.arraycopy(header.getBodyStartBit(), 0, bytes, pos,
                header.getBodyStartBit().length);
        pos = pos + header.getBodyStartBit().length;

        if (header.getBodyStartBit()[0] == Symbol.SYN) {

            System.arraycopy(header.getBodyCount(), 0, bytes, pos,
                    header.getBodyCount().length);
            pos = pos + header.getBodyCount().length;
        }

        System.arraycopy(body, 0, bytes, pos, body.length);
        pos = pos + body.length;

        // System.arraycopy(message.getEOF(), 0, bytes, pos, 1);
        bytes[pos] = message.getEOF();

        byte[] crcResult = CRC16Helper.crc16Check(bytes);

        // System.out.println(">> crcResult " +
        // ByteUtil.toHexString(crcResult));

        if (header.getStartBit()[0] == Symbol.SOH_ASC) {
            // 需要重新拼接为原字符串
            // 转换为字符串比较
            String calStr = ByteUtil.toHexString(crcResult);

            String crcStr = new String(message.getCRC());
            // System.out.println(">> crcStr " + crcStr);

            if (calStr.equalsIgnoreCase(crcStr)) {
                return true;
            } else {

                return false;
            }

        } else {
            if (Arrays.equals(crcResult, message.getCRC())) {

                return true;
            } else {
                return false;
            }
        }

    }

    /**
     * 根据设备号返回校时的时间，实现错峰数据上传
     * 当前时间-设备号/1000 求余数乘以10秒
     *
     * @param stcd
     * @return
     */
    public String getReplyDate(String stcd) {
        String staggeredShifts = Configurer.getStringProperty("staggered.shifts", "0");

        SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");
        String tm = "";
        if (staggeredShifts.equals("1")) {
            long rtucd = Long.parseLong(stcd);
            Integer delayMin = (int) ((rtucd - 5000) / 1000 * 20);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(Calendar.SECOND, delayMin);
            Date dt = calendar.getTime();
            tm = sdf.format(dt);
            logger.debug("设备号:" + stcd + ";延迟秒" + delayMin + "  下发的时间" + tm);
        } else {
            String replay4AHourAdd = Configurer.getStringProperty("hydro.replay4AHourAdd", "0");
            Calendar c = Calendar.getInstance();
            if (!replay4AHourAdd.equalsIgnoreCase("0")) {
                c.add(Calendar.HOUR_OF_DAY, Integer.parseInt(replay4AHourAdd));// 加一个小时
            }
            Date dt = c.getTime();

            tm = sdf.format(dt);
        }

        return tm;

    }

    public Long isDelay(IMessageHeader header, CommonMessage message) {
        Date now = new Date();
        long diff;
        long day = 0;
        long hour = 0;
        long min = 0;
        // 1、添加是否是升级程序，此处为2016-12-06新增程序
        try {
            // 解析报文体
            int serial = 0;
            IParser parserTm;
            parserTm = new HexParser();
            byte[] content = message.getContent();
            Date sendtime = null;
            if (header.getStartBit()[0] == Symbol.SOH_HEX) {
                byte[] serialid = new byte[2];
                System.arraycopy(content, 0, serialid, 0, serialid.length);
                serial = parserTm.parseSerial(new byte[]{content[0], content[1]});
                byte[] sendtimeBytes = new byte[6];
                System.arraycopy(content, serialid.length, sendtimeBytes, 0, sendtimeBytes.length);
                sendtime = parserTm.parseSendTime(sendtimeBytes);
            } else {
                serial = parserTm.parseSerial(new byte[]{content[0], content[1], content[2], content[3]});
                byte[] sendtimeBytes = new byte[12];
                System.arraycopy(content, 4, sendtimeBytes, 0, sendtimeBytes.length);
                sendtime = parserTm.parseSendTime(sendtimeBytes);

            }

            if (now.getTime() < sendtime.getTime()) {
                diff = sendtime.getTime() - now.getTime();
            } else {
                diff = now.getTime() - sendtime.getTime();
            }
            day = diff / (24 * 60 * 60 * 1000);
            hour = (diff / (60 * 60 * 1000) - day * 24);
            min = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return min;
    }

    /**
     * 构造HEX回复报文
     *
     * @param msg
     * @return
     */
    public byte[] replyMessage(IoSession session, CommonMessage message) {

        String messageInfo = com.godenwater.yanyu.utils.ByteUtil.toHexString(message.getContent());
        try {
            IMessageHeader header = (IMessageHeader) message.getHeader();

            // 取出序列值
            byte[] content = message.getContent();
            byte[] serialid;
            int seqid;
            if (header instanceof HexHeader) {
                serialid = new byte[2];
                System.arraycopy(content, 0, serialid, 0, 2);
                seqid = ByteUtil.bytesToUshort(serialid);
            } else {
                serialid = new byte[4];
                System.arraycopy(content, 0, serialid, 0, 4);
                String hexstr = new String(serialid);
                seqid = ByteUtil.bytesToUshort(ByteUtil
                        .HexStringToBinary(hexstr));
            }

            // 报文回复
            byte[] funcCode = header.getFuncCode();
            byte mode = header.getBodyStartBit()[0];

            DownCommand cmd = new DownCommand();
            cmd.setStartBit(header.getStartBit()[0]);
            cmd.setCenterAddr(header.getCenterAddr());
            cmd.setStationAddr(header.getStationAddr());
            cmd.setPassword(header.getPassword());
            cmd.setBodyStartBit(Symbol.STX);
            cmd.setFuncCode(funcCode);

            byte funccode = (byte) 0x2F;
            if (funcCode.length == 1) {
                funccode = funcCode[0];
            }
            if (funcCode.length == 2) {
                String hexFuncCode = new String(funcCode);
                funccode = ByteUtil.HexStringToBinary(hexFuncCode)[0];
            }

            String stcd = StcdParser.parseStcd(header.getStationAddr());
            String dt = getReplyDate(stcd);

            // ---------------------------------------------------------------------------
            // 如果上行的是升级程序回复，则需要下发升级报文，则在此做回复，此处为2016-12-06添加
            if (funccode == (byte) 0xE2) {// M1模式，无需应答
                // 判断如果是正常的上行报文，则下发升级程序命令
                // M2模式
                if (mode == Symbol.STX) {
                    if (message.getEOF() == Symbol.ACK) {
                        // 表示为应答报文，继续下发升级报文程序
                        RtuServer.getInstance().getSessionManager().bindUpgrade(session, stcd, "1", 0);// 用0是表示发所有的报

                        // -------------2016-12-09使用新下发开始---------------------------
                        // 下发所有的报文
                        //File file = getBinMessage(stcd);
                        // 读取文件内容，然后下发
                        //List<String> lines = FileUtils.readLines(file, "UTF-8");

                        //for (String line : lines) {
                        //	byte[] byteMessage = ByteUtil
                        //			.HexStringToBinary(line);

                        //		session.write(byteMessage);

                        //	Thread.sleep(2000);// 隔2秒自动重发下一包
                        //}
                        // -------------2016-12-09使用新下发结束---------------------------

                    }
                    if (message.getEOF() == Symbol.ETX) {
                        // 表示报文结束，后续无报文
                        if (isDelay(header, message) > 4) {
                            cmd.setEof(Symbol.ESC);
                        } else {
                            cmd.setEof(Symbol.EOT);
                        }
                        return HydroBuilder.toByte(cmd.sendReplyMessage(seqid, dt), cmd.getUpDown());
                    }
                }

                if (mode == Symbol.SYN) {
                    if (message.getEOF() == Symbol.NAK) {
                        // 表示否定回答，需要发送相对应的报文（判断如果是丢包命令，则下发丢包的报文）
                        // content,须将报文内容解析为缺报号
                        int count = ByteUtil.bytesToUshort(content);
                        RtuServer.getInstance().getSessionManager().bindUpgrade(session, stcd, "1", count);

                        // -------------2016-12-09使用新下发开始---------------------------
                        // 下发所有的报文
                        //File file = getBinMessage(stcd);
                        // 读取文件内容，然后下发
                        //List<String> lines = FileUtils.readLines(file, "UTF-8");

                        // 跳过多少行
                        //String line = lines.get(count);
                        //byte[] byteMessage = ByteUtil.HexStringToBinary(line);
                        //if (!session.isClosing()) {
                        //	session.write(byteMessage);
                        //}
                        // -------------2016-12-09使用新下发结束---------------------------

                    }
                    if (message.getEOF() == Symbol.EOT) {
                        // 表示报文结束，可以退出通信（ 发送如果是升级完成的回复，则更新状态）
                        return null;
                    }
                }
                return null;
            }
            String online = getStationByStcd(stcd);
            if (Configurer.getStringProperty("hydro.replay4AIs", "0").equals("1")) {
                Integer hour = new Date().getHours();
                if (hour != 0) {
                    online = "1";
                }
            }
            // ------------------------------------------------------------------------
            // 1、模式选择，如果是2F，不需要应答
            if (funccode != (byte) 0x2F) {// M1模式，无需应答

                // M2模式
                if (mode == Symbol.STX) {

                    // 2、判断结束符是哪种格式
                    // 2.1 ：在报文分包传输时作为结束符，表示未完成，不可退出通信
                    if (message.getEOF() == Symbol.ETB) {
                        // ACK 肯定确认，继续发送，作为有后续报文帧的“确认”结束符。
                        // NAK 否定应答，反馈重发， 用于要求对方重发某数据包的报文结束符。
                        // ENQ 作为下行查询及控制命令帧的报文结束符。
                        cmd.setEof(Symbol.ACK);
                        //判断是否在设置的范围回复1b 昆明熊岳
                       /* String hydroReplay1B = (String) Configurer.getProperty( "hydro.replay1b" );
                        String[] hydroRelay1BList = hydroReplay1B.split( "," );
                        for (int i = 0; i < hydroRelay1BList.length; i++) {
                            Long startCode = Long.parseLong( hydroRelay1BList[i].split( "-" )[0] );
                            Long endCode = Long.parseLong( hydroRelay1BList[i].split( "-" )[1] );
                            if (Long.parseLong( stcd ) >= startCode && Long.parseLong( stcd ) <= endCode) {
                                cmd.setEof( Symbol.ESC );
                            }
                        }*/


                    }

                    // 2.2：作为报文结束符，表示传输完成等待退出通信，
                    if (message.getEOF() == Symbol.ETX) {
                        cmd.setEof(Symbol.EOT);
                        // --- 反馈用EOT 作为传输结束确认帧报文符，表示可以退出通信。
                        // --- ESC 要求终端在线。保持在线10分钟内若没有接收到中心站命令，终端退回原先设定的工作状态
                      /*  if (isDelay( header, message ) > 4) {
                            cmd.setEof( Symbol.ESC );
                        } else {
                            cmd.setEof( Symbol.EOT );*/


                        if (online.equals("1")) {
                            cmd.setEof(Symbol.ESC);
                        }
                         /*   String hydroReplay1B = (String) Configurer.getProperty( "hydro.replay1b" );
                            if (!hydroReplay1B.equals( "" )) {
                                String[] hydroRelay1BList = hydroReplay1B.split( "," );
                                for (int i = 0; i < hydroRelay1BList.length; i++) {
                                    Long startCode = Long.parseLong( hydroRelay1BList[i].split( "-" )[0] );
                                    Long endCode = Long.parseLong( hydroRelay1BList[i].split( "-" )[1] );
                                    if (Long.parseLong( stcd ) >= startCode && Long.parseLong( stcd ) <= endCode) {
                                        cmd.setEof( Symbol.ESC );
                                    }
                                }
                            }*/
                        /* }*/

                        // 2.2.1
                        // 判断是否有召测信息，如果有，则需要将遥测站保持在线10分钟，见协议：6.2.2（2015-09-06新添加）
                    /*    int downCmdLen = checkCommand("SL651", stcd + "Callder");
                        if (downCmdLen > 0) {
                            cmd.setEof(cn.gov.mwr.sl651.Symbol.ESC);
                            // 表示有下发的报文，需要进行下发
                            RtuServer.getInstance().getSessionManager().bindCaller(session, stcd, "1");
                        }*/
                    }

                    return HydroBuilder.toByte(cmd.sendReplyMessage(seqid, dt), cmd.getUpDown());

                } else {
                    // M3模式
                    if (message.getEOF() == Symbol.ETB) {
                        // ETB不做应答
                        return null;
                    }

                    // 表示到最后一条报文
                    if (message.getEOF() == Symbol.ETX) {
                        cmd.setEof(Symbol.EOT);
                    }
                    return HydroBuilder.toByte(cmd.sendReplyMessage(seqid, dt), cmd.getUpDown());

                }

            } else {
                // M1模式，不做回答
                return null;
            }

        } catch (Exception e) {
            e.printStackTrace();
            logger.info("异常报文：" + messageInfo);
            logger.info(">> 构造回复报文出现异常！" + e.getMessage());
            return null;
        }
    }

    /**
     * 构造重发报文????有问题未完成
     *
     * @param msg
     * @return
     */
    public byte[] repeatMessage(CommonMessage message) {

        try {
            IMessageHeader header = (IMessageHeader) message.getHeader();

            byte[] content = message.getContent();
            byte[] serialid = new byte[2];
            if (content.length > 2) {
                System.arraycopy(content, 0, serialid, 0, 2);
            }
            // 报文回复
            byte[] funcCode = header.getFuncCode();
            byte mode = header.getBodyStartBit()[0];

            // 1、模式选择，如果是2F，不需要应答
            if (funcCode[0] != (byte) 0x2F) {// M1模式，无需应答

                if (mode == Symbol.STX) {
                    // M2模式，直接发送重发请求
                    DownCommand cmd = new DownCommand();
                    cmd.setCenterAddr(header.getCenterAddr());
                    cmd.setStationAddr(header.getStationAddr());
                    cmd.setPassword(header.getPassword());

                    cmd.setStartBit(header.getStartBit()[0]);
                    cmd.setBodyStartBit(Symbol.STX);
                    cmd.setFuncCode(funcCode);

                    cmd.setEof(Symbol.NAK);

                    return HydroBuilder.toByte(
                            cmd.sendRepeatMessage(
                                    ByteUtil.bytesToUshort(serialid), null),
                            cmd.getUpDown());
                } else {
                    // M3模式
                    if (message.getEOF() == Symbol.ETB) {
                        // 将错误报文，存储以将
                        // server.saveErrMessage(msg);
                        return null;
                    }

                    if (message.getEOF() == Symbol.ETX) {
                        // 将错误报文取出，并构建新报文，进行重发请求

                        return null;
                    }
                    return null;
                }
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.info(">> 构造重发报文出现异常！" + e.getMessage());
            return null;
        }
    }

    /**
     * 计算畅通率,添加畅通率计算 ,根据定时报32或者小时报34进行计算
     *
     * @param message
     * @return
     */
    public void rateMessage(String channel, byte funcCode, String stcd) {

        // ----------添加畅通率计算 ,根据定时报32或者小时报34进行计算-----------------

        try {
            if (funcCode == (byte) 0x32 || funcCode == (byte) 0x34) {
                // RtuServer.getInstance().getStationManager()
                // .updateRate(channel, stcd);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public String viewMessage(CommonMessage message) {
        IMessageHeader header = (IMessageHeader) message.getHeader();
        byte[] body = message.getContent();

        byte[] bytes = new byte[header.getLength() + body.length + 1];

        int pos = 0;
        System.arraycopy(header.getStartBit(), 0, bytes, pos,
                header.getStartBit().length);
        pos = pos + header.getStartBit().length; // 此处将取值直接改为取数据中字节的长度，对字节处理更精确

        System.arraycopy(header.getCenterAddr(), 0, bytes, pos,
                header.getCenterAddr().length);
        pos = pos + header.getCenterAddr().length;

        System.arraycopy(header.getStationAddr(), 0, bytes, pos,
                header.getStationAddr().length);
        pos = pos + header.getStationAddr().length;

        System.arraycopy(header.getPassword(), 0, bytes, pos,
                header.getPassword().length);
        pos = pos + header.getPassword().length;

        System.arraycopy(header.getFuncCode(), 0, bytes, pos,
                header.getFuncCode().length);
        pos = pos + header.getFuncCode().length;

        System.arraycopy(header.getBodySize(), 0, bytes, pos,
                header.getBodySize().length);
        pos = pos + header.getBodySize().length;

        System.arraycopy(header.getBodyStartBit(), 0, bytes, pos,
                header.getBodyStartBit().length);
        pos = pos + header.getBodyStartBit().length;

        if (header.getBodyStartBit()[0] == Symbol.SYN) {

            System.arraycopy(header.getBodyCount(), 0, bytes, pos,
                    header.getBodyCount().length);
            pos = pos + header.getBodyCount().length;
        }

        System.arraycopy(body, 0, bytes, pos, body.length);
        pos = pos + body.length;

        // System.arraycopy(message.getEOF(), 0, bytes, pos, 1);
        bytes[pos] = message.getEOF();

        String log = ByteUtil.toHexString(bytes)
                + ByteUtil.toHexString(message.getCRC());

        return log;
    }

    /**
     * 报文程序的目录
     *
     * @param protocol
     * @param stcd
     * @return
     */
    public File getBinMessage(String stcd) {

        String path = RtuConfig.getMsgBinPath();

        path = path + "/" + stcd + ".sbin";

        File fullPathDir = new File(path);
        if (fullPathDir != null && !fullPathDir.exists()) {
            fullPathDir.mkdirs();
        }

        File binFile = new File(path);

        if (binFile.exists()) {
            return binFile;
        } else {
            return null;
        }
    }

}
